function returnNumber(args:number):number {
  return 1;
}

function returnString(args:string):string {
  return '111';
}


function returnBoolean(args:boolean):boolean {
  return true;
}


// 以上的解决方案就行不通了
// 可以使用泛型  范式 / 规范  方法名字的后面<T> : T 或者 U K L X Y I

// 前端的范式 : 2015年之前 js + css2 + html5
// 前端的范式 : 2015年到2021年左右 大前端(全栈)node + typescript(2017) + react + vue + angular(2017) + react native(跨平台 ios/android) + flutter(google dart)
// 新的前端范式 :  微前端 (一个项目 嵌套多个项目) 中后台(BFF SSR SSG Model) CI/CD (构建工具) 检测工具 eslint prettier vue 

// 泛型 : 规范类型
function returnType<T>(args:T):T {
  return args;
}
// 1. 方法
const resNumber = returnType<number>(1);
resNumber.toFixed()

// 2. 接口
interface IABC<T> {
  (para : T):T
}
// abc123 : 函数  IABC<string>
const abc123:IABC<number> = (para:number) => 123

// 3. 类 T
class Stack<T>{
  private arr : Array<T> = []
  push(item:T){
    this.arr.push(item)
  }
}
const stack = new Stack<number>();
stack.push(12);

// swap : 使用泛型
// swap<number,string>([10,'20']) 得到结果==> ['20',10]
function swap<T,U>(tuple:[T,U]):[U,T]{
  return [tuple[1],tuple[0]]
}

const res2 = swap<boolean,string>([true,'123'])
console.log(res2)

// let obj = {name : 'zhang',age:10}
// 第二个参数 只能是obj里面的属性 比如 name / age : 得到的结果是 : obj['name'] 
// extends : 泛型里面叫约束类型
// getValue(obj,'name') 得到结果==> 'zhang'
// keyof : 索引类型  


interface ITest{
  name:string,
  age:string
}


interface ITest1{
  name:string
  pick:number,
  sex?:boolean
}


// Tkeys : 索引类型 : 索引的是ITest的每一个key
// & : 并  只要其中有一个有的 就可以  name age pick sex
// | : 交  name
type Tkeys = keyof (ITest & ITest1)
// let ta : ITest1 = 'name'

let ta1 : Tkeys = 'pick'


function test1<T extends object>(params:T){
}

test1({name:'124',age:'123'})

// extends : 约束类型
// keyof : 索引类型

// getValue(obj,'name') 得到结果==> 'zhang'

// keyof 接口
function getValue1<T extends object,U extends keyof T>(obj:T, key:U):T[U]{
  return obj[key]
}
const res3 = getValue1({name:'zhang',age:20.12303456},'name')
// 类型推断 : 根据值来推断类型
console.log(res3.includes('zh'))

// IMe : interface{ name:string,age:number} 
// IYou : interface{ num:string,pick:number}
// {name : 'zhang',age:20}  , {num:'123',pick:12}
// result : {name:'zhang',age:20,num:'123',pick:12}
// extend<IMe,IYou>(first:IMe,second:IYou) : => IMe & IYou 
//{IMe 和 IYOu 可以合并成一个新的值}
// 实现  extend<IMe,IYou>(first:IMe,second:IYou) 
// 交叉类型 和 联合类型

function extend<T,U>(first:T,second:U) : T & U{
  // as 是类型断言
  // 当做 先赋值 在进行类型的推断
  // let result = {} as T & U;
  let res : T & U = {} as T & U;
  function combine(obj1:T,obj2:U){
    // Object assign : 合并多个对象 
    Object.assign(res,obj1,obj2);
  }
  combine(first,second)
  return res
}

function combine<T, U> (first: T, second: U): T & U {
  let result = {} as T & U;
  for (let key in first) {
    // @ts-ignore : 忽略掉这个错误
    result[key] = first[key];
  }
  for (let key in second) {
    // @ts-ignore : 忽略掉这个错误
    result[key] = second[key];
  }
  return result;
}
interface IMe{
  name : string,
  message : string
}
interface IYou{
  user: string,
  password : string 
}

const res4 = combine<IMe,IYou>({name:'zhangsa',message:'hello'}, {user:'lisi',password:'admin'})
const res5 = extend<IMe,IYou>({name:'zhangsa',message:'hello'}, {user:'lisi',password:'admin'})
console.log(res5)


